package com.kvn.backdoor.web;

import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.lang.reflect.ParameterizedType;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 异常翻译器
 * Created by wangzhiyuan on 2018/8/20
 */
public interface ExceptionInterpreter<T extends Exception> {
    /**
     * 将异常翻译成前端展示的信息
     * @param e
     * @return
     */
    String translateExceptionMsg(T e);

    Map<Class, ExceptionInterpreter> exceptionInterpreterMap = new HashMap<>();
    static void init(){
        if (exceptionInterpreterMap.size() > 0) {
            return;
        }

        Class<?>[] declaredClasses = ExceptionInterpreter.class.getDeclaredClasses();
        for (Class<?> declaredClass : declaredClasses) {
            if (ExceptionInterpreter.class.isAssignableFrom(declaredClass)) {
                try {
                    ParameterizedType type = (ParameterizedType) declaredClass.getGenericInterfaces()[0];
                    exceptionInterpreterMap.put((Class) type.getActualTypeArguments()[0], (ExceptionInterpreter) declaredClass.newInstance());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    static ExceptionInterpreter getExceptionInterpreter(Class<? extends Exception> clazz){
        init();
        AtomicReference<ExceptionInterpreter> interpreter = new AtomicReference<>();
        exceptionInterpreterMap.forEach((key, value) -> {
            if (key == Exception.class) {
                return; // 相当于普通for 循环中的 continue
            }

            if (key.isAssignableFrom(clazz)) {
                interpreter.set(value);
                return;
            }
        });
        return interpreter.get() == null ? exceptionInterpreterMap.get(Exception.class) : interpreter.get();
    }

    public static void main(String[] args) {
//        ExceptionInterpreter exceptionInterpreter = getExceptionInterpreter(IllegalArgumentException.class);
        ExceptionInterpreter exceptionInterpreter = getExceptionInterpreter(BindException.class);
        System.out.println("args = [" + exceptionInterpreter + "]");
    }


    class DefaultExceptionInterpreter implements ExceptionInterpreter<Exception> {

        @Override
        public String translateExceptionMsg(Exception e) {
            StringBuilder errorMsg = new StringBuilder("系统异常");
            return errorMsg.append("->").append(e.getMessage()).toString();
        }
    }

    class MethodArgumentNotValidExceptionInterpreter implements ExceptionInterpreter<MethodArgumentNotValidException> {

        @Override
        public String translateExceptionMsg(MethodArgumentNotValidException e) {
            StringBuilder errorMsg = new StringBuilder("系统异常");
            List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
            errorMsg.append("->参数异常：");
            for (ObjectError error : allErrors) {
                errorMsg.append('\n');
                if (error instanceof FieldError) {
                    errorMsg.append("field:").append(((FieldError) error).getField()).append(",");
                }
                errorMsg.append(error.getDefaultMessage());
            }
            return errorMsg.toString();
        }
    }

    class ConstraintViolationExceptionInterpreter implements ExceptionInterpreter<ConstraintViolationException> {

        @Override
        public String translateExceptionMsg(ConstraintViolationException e) {
            StringBuilder errorMsg = new StringBuilder("系统异常");
            Set<ConstraintViolation<?>> violationSet = e.getConstraintViolations();
            Iterator<ConstraintViolation<?>> it = violationSet.iterator();
            errorMsg.append("->参数异常：");
            while (it.hasNext()) {
                errorMsg.append('\n');
                ConstraintViolation<?> violation = it.next();
                errorMsg.append(violation.getPropertyPath()).append(":").append(violation.getMessage());
            }
            return errorMsg.toString();
        }
    }

    class BindExceptionInterpreter implements ExceptionInterpreter<BindException> {

        @Override
        public String translateExceptionMsg(BindException e) {
            StringBuilder errorMsg = new StringBuilder("系统异常");
            List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
            errorMsg.append("->参数异常：");
            for (ObjectError error : allErrors) {
                errorMsg.append('\n');
                if (error instanceof FieldError) {
                    errorMsg.append("field:").append(((FieldError) error).getField()).append(",");
                }
                errorMsg.append(error.getDefaultMessage());
            }
            return errorMsg.toString();
        }
    }
}
